package com.ssy.lingxi.settle.accounts.serviceimpl;

import cn.hutool.core.collection.CollectionUtil;
import com.ssy.lingxi.common.constant.settle.SettlementTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.settle.accounts.entity.PlatformSettlementStrategyDO;
import com.ssy.lingxi.settle.accounts.entity.PlatformSettlementStrategyMemberDO;
import com.ssy.lingxi.settle.accounts.model.constant.CommonBooleanEnum;
import com.ssy.lingxi.settle.accounts.model.constant.PlatformSettlementOrderTypeEnum;
import com.ssy.lingxi.settle.accounts.model.constant.SettlementStrategyStatusEnum;
import com.ssy.lingxi.settle.accounts.model.constant.SettlementWayEnum;
import com.ssy.lingxi.settle.accounts.model.vo.request.*;
import com.ssy.lingxi.settle.accounts.model.vo.response.PlatformSettlementStrategyDetailVO;
import com.ssy.lingxi.settle.accounts.model.vo.response.PlatformSettlementStrategyMemberVO;
import com.ssy.lingxi.settle.accounts.model.vo.response.PlatformSettlementStrategyVO;
import com.ssy.lingxi.settle.accounts.repository.PlatformSettlementStrategyMemberRepository;
import com.ssy.lingxi.settle.accounts.repository.PlatformSettlementStrategyRepository;
import com.ssy.lingxi.settle.accounts.service.IPlatformSettlementStrategyService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 平台结算策略接口实现
 * @author 伍将
 * @date 2020/11/4
 * @version 2.0.0
 */
@Service
public class PlatformSettlementStrategyServiceImpl implements IPlatformSettlementStrategyService {

    @Resource
    private PlatformSettlementStrategyRepository repository;

    @Resource
    private PlatformSettlementStrategyMemberRepository memberRepository;

    /**
     * 分页查询平台结算策略
     * @author 伍将
     * @date 2020/11/4
     * @param sysUser:
     * @param pageVO:
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.common.response.PageData < com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformSettlementStrategyVO>>
     **/
    @Override
    public Wrapper<PageData<PlatformSettlementStrategyVO>> pageStrategy(UserLoginCacheDTO sysUser, PlatformSettlementStrategyPageVO pageVO) {

        // step 1: 组装查询条件
        Specification<PlatformSettlementStrategyDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if (StringUtils.hasLength(pageVO.getName())) {
                list.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + pageVO.getName().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // step 2: 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("status").descending());

        // step 3: 分页查询数据
        Page<PlatformSettlementStrategyDO> result = repository.findAll(spec, page);

        // step 4: 组装数据
        List<PlatformSettlementStrategyVO> resultList = result.getContent().stream().map(r -> {
            PlatformSettlementStrategyVO queryVO = new PlatformSettlementStrategyVO();
            queryVO.setId(r.getId());
            queryVO.setName(r.getName());
            queryVO.setSettlementWayName(SettlementWayEnum.getMessage(r.getSettlementWay()));
            queryVO.setSettlementOrderTypeName(PlatformSettlementOrderTypeEnum.getMessage(r.getSettlementOrderType()));
            queryVO.setStatus(r.getStatus());
            queryVO.setStatusName(SettlementStrategyStatusEnum.getMessage(r.getStatus()));
            queryVO.setSettlementPaymentTypeName(SettlementTypeEnum.getName(r.getSettlementPaymentType()));
            return queryVO;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * 设置平台结算策略状态
     * @author 伍将
     * @date 2020/11/4
     * @param sysUser: 
     * @param setStatusVO: 
     * @return com.ssy.lingxi.common.response.Wrapper
     **/
    @Transactional
    @Override
    public Wrapper<Void> setStatus(UserLoginCacheDTO sysUser, PlatformSettlementStrategySetStatusVO setStatusVO) {

        PlatformSettlementStrategyDO entity = repository.findById(setStatusVO.getId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_NOT_EXIST);
        }

        entity.setStatus(setStatusVO.getStatus());
        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 当设置策略为有效时需要验证下属成员是否存在多个有效策略中
        if (entity.getStatus().equals(SettlementStrategyStatusEnum.VALID.getCode())) {

            Boolean isExists;
            // 当前策略为默认策略时，检查是否存在其他策略
            if (entity.getIsDefault().equals(CommonBooleanEnum.YES.getCode())) {
                isExists = repository.existsByStatusAndSettlementOrderTypeAndIdNot(SettlementStrategyStatusEnum.VALID.getCode(), entity.getSettlementOrderType(), entity.getId());
            } else {
                //验证策略下平台是否拥有其他默认结算策略
                isExists = repository.existsByIsDefaultAndStatusAndSettlementOrderType(CommonBooleanEnum.YES.getCode(),
                        SettlementStrategyStatusEnum.VALID.getCode(), entity.getSettlementOrderType());
            }
            if (isExists) {
                throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_MEMBER_USED);
            }

            isExists = existsStrategy(entity);
            if (isExists) {
                throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_MEMBER_USED);
            }
        }

        return Wrapper.success();
    }

    /**
     * 查询平台结算策略详情
     * @author 伍将
     * @date 2020/11/4
     * @param id: 
     * @return com.ssy.lingxi.common.response.Wrapper<com.ssy.lingxi.settle.accounts.mode.vo.response.PlatformSettlementStrategyDetailVO>
     **/
    @Override
    public Wrapper<PlatformSettlementStrategyDetailVO> getDetail(Long id) {
        PlatformSettlementStrategyDO entity = repository.findById(id).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_NOT_EXIST);
        }

        PlatformSettlementStrategyDetailVO result = new PlatformSettlementStrategyDetailVO();
        result.setId(entity.getId());
        result.setName(entity.getName());
        result.setSettlementDate(entity.getSettlementDate());
        result.setEstimatedPaymentDate(entity.getEstimatedPaymentDate());
        result.setSettlementDays(entity.getSettlementDays());
        result.setSettlementOrderType(entity.getSettlementOrderType());
        result.setSettlementWay(entity.getSettlementWay());
        result.setStatus(entity.getStatus());
        result.setIsDefault(entity.getIsDefault());
        result.setSettlementPaymentType(entity.getSettlementPaymentType()); // 结算支付方式
        result.setSettlementPaymentTypeName(SettlementTypeEnum.getName(entity.getSettlementPaymentType())); // 结算支付名称
        List<PlatformSettlementStrategyMemberDO> memberDOList = entity.getMemberList();
        if (memberDOList != null && memberDOList.size() > 0) {

            List<PlatformSettlementStrategyMemberVO> memberList = memberDOList.stream().map(r -> {
                PlatformSettlementStrategyMemberVO queryVO = new PlatformSettlementStrategyMemberVO();
                queryVO.setMemberId(r.getMemberId());
                queryVO.setRoleId(r.getRoleId());
                queryVO.setMemberName(r.getMemberName());
                queryVO.setRoleName(r.getRoleName());
                queryVO.setMemberTypeName(r.getMemberTypeName());
                queryVO.setLevelName(r.getLevelName());
                return queryVO;
            }).collect(Collectors.toList());

            result.setMemberList(memberList);
        }


        return Wrapper.success(result);
    }

    /**
     * 新增平台结算策略
     * @author 伍将
     * @date 2020/11/4
     * @param addVO: 
     * @return com.ssy.lingxi.common.response.Wrapper<java.lang.Long>
     **/
    @Transactional
    @Override
    public Wrapper<Long> add(UserLoginCacheDTO sysUser, PlatformSettlementStrategyAddVO addVO) {

        PlatformSettlementStrategyDO entity = new PlatformSettlementStrategyDO();
        entity.setName(addVO.getName());
        entity.setSettlementWay(addVO.getSettlementWay());
        entity.setSettlementDate(addVO.getSettlementDate());
        entity.setSettlementDays(addVO.getSettlementDays());
        entity.setEstimatedPaymentDate(addVO.getEstimatedPaymentDate());
        entity.setSettlementOrderType(addVO.getSettlementOrderType());
        entity.setSettlementPaymentType(addVO.getSettlementPaymentType()); // 设置结算支付方式
        entity.setStatus(SettlementStrategyStatusEnum.VALID.getCode()); // 默认为有效
        entity.setIsDefault(addVO.getIsDefault());
        entity.setCreateTime(System.currentTimeMillis());
        entity.setUpdateTime(0L);

        //验证策略下平台是否拥有多个结算策略
        if (entity.getIsDefault().equals(CommonBooleanEnum.YES.getCode())) {
            // 策略为默认时，检查是否存在其他策略
            Boolean isExists = repository.existsByStatusAndSettlementOrderType(SettlementStrategyStatusEnum.VALID.getCode(), entity.getSettlementOrderType());
            if (isExists) {
                throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_MEMBER_USED);
            }
        } else {
            // 策略为非默认时，检查是否存在默认策略
            Boolean isExists = repository.existsByIsDefaultAndStatusAndSettlementOrderType(CommonBooleanEnum.YES.getCode(), SettlementStrategyStatusEnum.VALID.getCode(), entity.getSettlementOrderType());
            if (isExists) {
                throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_MEMBER_USED);
            }

            // 组装策略下会员
            if (addVO.getMemberList() != null && addVO.getMemberList().size() > 0) {
                List<PlatformSettlementStrategyMemberDO> memberList = addVO.getMemberList().stream().distinct().map(r -> {
                    PlatformSettlementStrategyMemberDO member = new PlatformSettlementStrategyMemberDO();
                    member.setMemberId(r.getMemberId());
                    member.setRoleId(r.getRoleId());
                    member.setMemberName(r.getMemberName());
                    member.setRoleName(r.getRoleName());
                    member.setMemberTypeName(r.getMemberTypeName());
                    member.setLevelName(r.getLevelName());
                    member.setStrategy(entity);
                    return member;
                }).collect(Collectors.toList());
                entity.setMemberList(memberList);
            }
        }

        repository.saveAndFlush(entity);

        // 当结算策略为有效时，验证策略下会员是否拥有多个结算策略
        Boolean isExists = existsStrategy(entity);
        if (isExists) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_MEMBER_USED);
        }

        return Wrapper.success(entity.getId());
    }

    /**
     * 更新平台结算策略
     * @author 伍将
     * @date 2020/11/4
     * @param updateVO: 
     * @return com.ssy.lingxi.common.response.Wrapper<java.lang.Long>
     **/
    @Transactional
    @Override
    public Wrapper<Long> update(UserLoginCacheDTO sysUser, PlatformSettlementStrategyUpdateVO updateVO) {

        PlatformSettlementStrategyDO entity = repository.findById(updateVO.getId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_NOT_EXIST);
        }

        entity.setName(updateVO.getName());
        entity.setSettlementWay(updateVO.getSettlementWay());
        entity.setSettlementDate(updateVO.getSettlementDate());
        entity.setEstimatedPaymentDate(updateVO.getEstimatedPaymentDate());
        entity.setSettlementDays(updateVO.getSettlementDays());
        entity.setSettlementOrderType(updateVO.getSettlementOrderType());
        entity.setIsDefault(updateVO.getIsDefault());
        entity.setUpdateTime(System.currentTimeMillis());
        // 修改结算支付方式
        entity.setSettlementPaymentType(updateVO.getSettlementPaymentType());

        if (entity.getStatus().equals(SettlementStrategyStatusEnum.VALID.getCode())) {

            Boolean isExists;
            // 如果当前策略为默认，检查是否存在其他策略
            if (entity.getIsDefault().equals(CommonBooleanEnum.YES.getCode())) {
                isExists = repository.existsByStatusAndSettlementOrderTypeAndIdNot(SettlementStrategyStatusEnum.VALID.getCode(), entity.getSettlementOrderType(), entity.getId());
            }
            //验证策略下平台是否拥有默认结算策略
            else {
                isExists = repository.existsByIsDefaultAndStatusAndSettlementOrderType(CommonBooleanEnum.YES.getCode(),
                        SettlementStrategyStatusEnum.VALID.getCode(), entity.getSettlementOrderType());
            }
            if (isExists) {
                throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_MEMBER_USED);
            }
        }

        repository.saveAndFlush(entity);

        // 删除原始策略下会员
        memberRepository.deleteByStrategyId(entity.getId());

        // 保存策略下会员
        if (updateVO.getMemberList() != null && updateVO.getMemberList().size() > 0) {

            List<PlatformSettlementStrategyMemberDO> memberList = updateVO.getMemberList().stream().distinct().map(r -> {
                PlatformSettlementStrategyMemberDO member = new PlatformSettlementStrategyMemberDO();
                member.setMemberId(r.getMemberId());
                member.setRoleId(r.getRoleId());
                member.setMemberName(r.getMemberName());
                member.setRoleName(r.getRoleName());
                member.setMemberTypeName(r.getMemberTypeName());
                member.setLevelName(r.getLevelName());
                member.setStrategy(entity);
                return member;
            }).collect(Collectors.toList());
            entity.setMemberList(memberList);

            // 当结算策略为有效时，验证策略下会员是否拥有多个结算策略
            if (entity.getStatus().equals(SettlementStrategyStatusEnum.VALID.getCode())) {
                Boolean isExists = existsStrategy(entity);
                if (isExists) {
                    throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_MEMBER_USED);
                }
            }
        }

        return Wrapper.success();
    }

    /**
     * 检查结算策略是否存在
     * @author 伍将
     * @date 2020/11/4
     * @param strategyDO:
     * @return java.lang.Boolean
     **/
    private Boolean existsStrategy(PlatformSettlementStrategyDO strategyDO) {

        boolean isExists = false;
        // 当前策略为有效时才验证
        if (CollectionUtil.isNotEmpty(strategyDO.getMemberList())&&strategyDO.getStatus().equals(SettlementStrategyStatusEnum.VALID.getCode())) {

            // 查询同类型单据数据
            List<PlatformSettlementStrategyDO> strategyList = repository.findByStatusAndSettlementOrderType(strategyDO.getStatus(), strategyDO.getSettlementOrderType());

            List<String> tempList = strategyDO.getMemberList().stream()
                    .map(r -> r.getMemberId().toString() + r.getRoleId().toString()
                    ).collect(Collectors.toList());

            // 检查策略成员是否在多个策略中
            isExists = strategyList.stream().filter(
                    o -> !o.getId().equals(strategyDO.getId()))
                    .collect(Collectors.toList())
                    .stream().anyMatch(
                            o -> o.getMemberList().stream().anyMatch(
                                    item -> tempList.contains(item.getMemberId().toString() + item.getRoleId().toString())
                            )
                    );
        }
        return isExists;
    }

    /**
     * 删除平台结算策略
     * @author 伍将
     * @date 2020/12/24
     * @param sysUser:
     * @param deleteVO:
     **/
    @Override
    public Wrapper<Void> delete(UserLoginCacheDTO sysUser, PlatformSettlementStrategyDeleteVO deleteVO) {

        PlatformSettlementStrategyDO entity = repository.findById(deleteVO.getId()).orElse(null);
        if (entity == null) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_NOT_EXIST);
        }
        if (entity.getStatus().equals(SettlementStrategyStatusEnum.VALID.getCode())) {
            throw new BusinessException(ResponseCode.SA_PLATFORM_SETTLEMENT_STRATEGY_CAN_NOT_DELETE);
        }

        repository.delete(entity);

        return Wrapper.success();
    }
}
